package com.fingard.remoting.server;

import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import com.fingard.FGBiz;
import com.fingard.dsp.tcpserver.RequestNIO;
import com.fingard.dsp.tcpserver.SocketReceiver;
import com.fingard.remoting.client.TenantClient;
import com.fingard.text.XmlHelper;

public class TenantServer {

	private TenantSet tenantSet;
	public boolean isEnable(){
		if(tenantSet!=null){
			return tenantSet.enable;
		}else{
			return false;
		}
	}
	public boolean isRemoting(String pTenant){
		if(tenantSet!=null && tenantSet.hasTenant(pTenant)){
			return true;
		}else{
			return false;
		}
	}
	
	private ScheduledExecutorService pool;
	TenantServerTimer tsTimer;
	
	public TenantServer(){
		String filePath = FGBiz.DSPHOME+File.separator+"config"+File.separator+"TenantRemoting.xml";
		tenantSet = new TenantSet();
		tenantSet.loadFromXmlFile(filePath);
		if(tenantSet.enable){
			mapConnection = new HashMap<String,ArrayList<RequestNIO>>();
			
			pool = Executors.newScheduledThreadPool(1);
			tsTimer = new TenantServerTimer(mapConnection);
            pool.scheduleWithFixedDelay(tsTimer, 5, 5, TimeUnit.SECONDS);
			
		}
	}
	HashMap<String,ArrayList<RequestNIO>> mapConnection;
	public void addConnection(RequestNIO pReq) throws Exception{
		if(tenantSet.enable){
			String tmpStrReq = new String(pReq.reqSocketReceiver.reqBytes, pReq.reqSocketReceiver.contentStartIndex, pReq.reqSocketReceiver.contentLength, pReq.reqSocketReceiver.charsetName);
			String[] sp = tmpStrReq.split("\r\n");
			if(sp.length>0){
				for(int i=0;i<sp.length;i++){
					String[] kvs = sp[i].split(":");
					if(kvs.length>1){
						if("tenant".equals(kvs[0])){
							pReq.reqSocketReceiver.tenant = kvs[1].trim();
						}else if("cipher-key".equals(kvs[0])){
							pReq.reqSocketReceiver.cipherKey = kvs[1].trim();
						}else if("cipher-iv".equals(kvs[0])){
							pReq.reqSocketReceiver.cipherIV = kvs[1].trim();
						}
					}
				}
			}
			FGBiz.limitMsg.addConsole("TenantServer.addConnection", "租户："+pReq.reqSocketReceiver.tenant);
			pReq.bankHeader.tenant = pReq.reqSocketReceiver.tenant;
			
			if(mapConnection.containsKey(pReq.bankHeader.tenant)){
				ArrayList<RequestNIO> aList = mapConnection.get(pReq.bankHeader.tenant);
				removeList(aList);
				aList.add(pReq);
			}else{
				ArrayList<RequestNIO> nList = new ArrayList<RequestNIO>();
				nList.add(pReq);
				mapConnection.put(pReq.bankHeader.tenant, nList);
			}
			pReq.reqSocketReceiver.clientSocketChannel.configureBlocking(true);
			byte[] bytesResp = getBytes("<resp>ok</resp>","gbk");
			try {
				pReq.writeBytes(bytesResp);
			} catch (Throwable e) {
				pReq.reqSocketReceiver.isNeedCloseConn = true;
				FGBiz.limitMsg.exception("TenantServer.addConnection", e);
			}
		}else{
			throw new Exception("未启用租户远程服务");
		}
	}
	
	private void removeList(ArrayList<RequestNIO> pList){
		if(pList.size()>0){
			int count = pList.size();
			for(int i=count-1;i>=0;i--){
				RequestNIO eachReq = pList.get(i);
				try {
					if(eachReq !=null && eachReq.reqSocketReceiver != null && eachReq.reqSocketReceiver.clientSocketChannel != null){
						
						eachReq.reqSocketReceiver.clientSocketChannel.close();
						eachReq = null;
					}
				} catch (Throwable e) {
					FGBiz.limitMsg.exception("TenantServer.getRequestNIO", e);
				}
				pList.remove(i);
			}
			
		}
	}
	
	private RequestNIO getRequestNIO(String pTenant){
		if(mapConnection!= null && mapConnection.containsKey(pTenant)){
			ArrayList<RequestNIO> aList = mapConnection.get(pTenant);
			while(aList.size()>0){
				RequestNIO eachReq = aList.get(0);
				if(eachReq ==null || eachReq.reqSocketReceiver ==null || eachReq.reqSocketReceiver.clientSocketChannel==null){
					aList.remove(0);
				}else if(eachReq.reqSocketReceiver.isNeedCloseConn){
					try {
						eachReq.reqSocketReceiver.clientSocketChannel.close();
					} catch (Throwable e) {
						FGBiz.limitMsg.exception("TenantServer.getRequestNIO", e);
					}
					aList.remove(0);
				}else{
					return eachReq;
				}
			}
		}
		return null;
	}
	
	public static byte[] getBytes(String pReqStr, String pCharset) throws UnsupportedEncodingException{

		byte[] tmpBytesBody = pReqStr.getBytes(pCharset);

        String tmpStrLen = String.format("% 8d", tmpBytesBody.length);

        String tmpRespHead = "Content-Length:" + tmpStrLen + "\r\n";
        byte[] tmpBytesHead = tmpRespHead.getBytes(pCharset);

        byte[] tmpBytesResp = new byte[tmpBytesHead.length + tmpBytesBody.length];
        System.arraycopy(tmpBytesHead, 0, tmpBytesResp, 0, tmpBytesHead.length);
        System.arraycopy(tmpBytesBody, 0, tmpBytesResp, tmpBytesHead.length, tmpBytesBody.length);
        return tmpBytesResp;
	}
	
	public String remotingInvoke(String pTenant, String pReqStr) throws Throwable{
		RequestNIO remoting = getRequestNIO(pTenant);
		if(remoting!=null){
			byte[] toWriteBytes = getBytes(pReqStr,remoting.reqSocketReceiver.charsetName);
			synchronized(remoting.reqSocketReceiver){
				remoting.writeBytes(toWriteBytes);
				remoting.reqSocketReceiver.reset();
				remoting.recByteBuffer = null;
				remoting.receiveBytes();
				String tmpStrReq = new String(remoting.reqSocketReceiver.reqBytes, remoting.reqSocketReceiver.contentStartIndex, remoting.reqSocketReceiver.contentLength, remoting.reqSocketReceiver.charsetName);
				return tmpStrReq;
			}
		}else{
			return "<ATSYH><TransResp><TransParam><RespCode>-1</RespCode><RespInfo>远程租户端未连接</RespInfo></TransParam></TransResp></ATSYH>";
		}
	}
}
